//
//  IMLogUtils.m
//  DualMediationSDK
//
//  Created by YeJary on 2025/6/23.
//

#import "IMLogUtils.h"
#import <sys/utsname.h>
#import <mach/mach.h>
#import <os/log.h>

// 文件相关常量
static const NSUInteger kDefaultMaxFileSize = 10 * 1024 * 1024;  // 10MB
static const NSUInteger kDefaultMaxFileCount = 10;
static const NSTimeInterval kDefaultAutoCleanInterval = 24 * 60 * 60;  // 24小时
static const NSTimeInterval kDefaultMaxFileAge = 7 * 24 * 60 * 60;     // 7天

@implementation IMLogConfig

+ (instancetype)defaultConfig {
    IMLogConfig *config = [[IMLogConfig alloc] init];
    config.level = IMLogLevelInfo;
    config.enableConsoleLog = YES;
    config.enableFileLog = YES;
    config.enableUpload = NO;
    config.maxFileSize = kDefaultMaxFileSize;
    config.maxFileCount = kDefaultMaxFileCount;
    config.autoCleanInterval = kDefaultAutoCleanInterval;
    config.maxFileAge = kDefaultMaxFileAge;
    config.enableSensitiveFilter = YES;
    return config;
}

+ (instancetype)debugConfig {
    IMLogConfig *config = [self defaultConfig];
    config.level = IMLogLevelVerbose;
    config.enableConsoleLog = YES;
    config.enableFileLog = YES;
    config.enableUpload = NO;
    config.enableSensitiveFilter = NO;
    return config;
}

+ (instancetype)releaseConfig {
    IMLogConfig *config = [self defaultConfig];
    config.level = IMLogLevelWarning;
    config.enableConsoleLog = YES; // Use os_log in Release as well
    config.enableFileLog = YES;
    config.enableUpload = YES;
    config.enableSensitiveFilter = YES;
    return config;
}

@end

@interface IMLogUtils ()

@property (nonatomic, strong) IMLogConfig *config;
@property (nonatomic, strong) dispatch_queue_t logQueue;
@property (nonatomic, strong) NSFileManager *fileManager;
@property (nonatomic, strong) NSDateFormatter *dateFormatter;
@property (nonatomic, strong) NSString *currentLogFilePath;
@property (nonatomic, strong) NSFileHandle *fileHandle;
@property (nonatomic, strong) NSTimer *cleanTimer;
@property (nonatomic) dispatch_source_t cleanDispatchTimer;
@property (nonatomic, assign) os_log_t osLog;
@property (nonatomic, copy) IMLogMonitorCallback logMonitorCallback;

+ (os_log_type_t)osLogTypeForLevel:(IMLogLevel)level;

@end

@implementation IMLogUtils

static IMLogUtils *_instance = nil;
static dispatch_once_t onceToken;

+ (instancetype)sharedInstance {
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init];
    });
    return _instance;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        _logQueue = dispatch_queue_create("com.dualmediation.log", DISPATCH_QUEUE_SERIAL);
        _fileManager = [NSFileManager defaultManager];
        _dateFormatter = [[NSDateFormatter alloc] init];
        _dateFormatter.dateFormat = @"yyyy-MM-dd HH:mm:ss.SSS";
        _dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
        if (@available(iOS 10.0, *)) {
            _osLog = os_log_create("com.dualmediation", "IMLogUtils");
        } else {
            _osLog = OS_LOG_DEFAULT;
        }
        
        // 设置默认配置，确保在initWithConfig调用之前也能正常工作
        _config = [IMLogConfig defaultConfig];
    }
    return self;
}

#pragma mark - Public Methods

+ (void)initWithConfig:(IMLogConfig *)config {
    IMLogUtils *instance = [self sharedInstance];
    instance.config = config ?: [IMLogConfig defaultConfig];
    
    // 设置日志目录
    if (!instance.config.logDirectory) {
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsPath = [paths firstObject];
        instance.config.logDirectory = [documentsPath stringByAppendingPathComponent:@"IMLogs"];
    }
    
    // 创建日志目录
    if (![instance.fileManager fileExistsAtPath:instance.config.logDirectory]) {
        [instance.fileManager createDirectoryAtPath:instance.config.logDirectory withIntermediateDirectories:YES attributes:nil error:nil];
    }
    
    // 设置当前日志文件
    [instance setupCurrentLogFile];
    
    // 启动自动清理定时器
    [instance startAutoCleanTimer];
    
    // 初始化后立即触发一次清理，避免首次启动时保留过期/超量旧日志
    [instance triggerLogCleanup];
    
    [IMLogUtils info:IMLogTagSDKInit format:@"日志系统初始化完成，目录：%@", instance.config.logDirectory];
}

+ (IMLogConfig *)currentConfig {
    return [self sharedInstance].config ?: [IMLogConfig defaultConfig];
}

+ (void)setLogLevel:(IMLogLevel)level {
    [self sharedInstance].config.level = level;
}

+ (IMLogLevel)currentLogLevel {
    return [self sharedInstance].config.level;
}

+ (void)enableLog:(BOOL)enable {
    if (enable) {
        [self sharedInstance].config.level = [self isDebugEnvironment] ? IMLogLevelVerbose : IMLogLevelInfo;
    } else {
        [self sharedInstance].config.level = IMLogLevelOff;
    }
}

+ (BOOL)isDebugEnvironment {
#ifdef DEBUG
    return YES;
#else
    return NO;
#endif
}

#pragma mark - Basic Log Methods

+ (void)verbose:(IMLogTag)tag format:(NSString *)format, ... {
    if ([self currentLogLevel] > IMLogLevelVerbose || ![self isDebugEnvironment]) return;
    
    va_list args;
    va_start(args, format);
    NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
    va_end(args);
    
    [self logWithLevel:IMLogLevelVerbose tag:tag message:message];
}

+ (void)debug:(IMLogTag)tag format:(NSString *)format, ... {
    if ([self currentLogLevel] > IMLogLevelDebug || ![self isDebugEnvironment]) return;
    
    va_list args;
    va_start(args, format);
    NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
    va_end(args);
    
    [self logWithLevel:IMLogLevelDebug tag:tag message:message];
}

+ (void)info:(IMLogTag)tag format:(NSString *)format, ... {
    if ([self currentLogLevel] > IMLogLevelInfo) return;
    
    va_list args;
    va_start(args, format);
    NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
    va_end(args);
    
    [self logWithLevel:IMLogLevelInfo tag:tag message:message];
}

+ (void)warning:(IMLogTag)tag format:(NSString *)format, ... {
    if ([self currentLogLevel] > IMLogLevelWarning) return;
    
    va_list args;
    va_start(args, format);
    NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
    va_end(args);
    
    [self logWithLevel:IMLogLevelWarning tag:tag message:message];
}

+ (void)error:(IMLogTag)tag format:(NSString *)format, ... {
    if ([self currentLogLevel] > IMLogLevelError) return;
    
    va_list args;
    va_start(args, format);
    NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
    va_end(args);
    
    [self logWithLevel:IMLogLevelError tag:tag message:message];
}

#pragma mark - Special Log Methods

+ (void)logAdEvent:(NSString *)event adUnitId:(NSString *)adUnitId params:(NSDictionary *)params {
    NSMutableString *message = [NSMutableString stringWithFormat:@"[AdEvent] %@ - %@", event, adUnitId];
    if (params.count > 0) {
        [message appendFormat:@" - %@", [self dictionaryToJSONString:params]];
    }
    [self logWithLevel:IMLogLevelInfo tag:IMLogTagAdRequest message:message];
}

+ (void)logNetworkRequest:(NSString *)url method:(NSString *)method statusCode:(NSInteger)statusCode duration:(NSTimeInterval)duration {
    NSString *message = [NSString stringWithFormat:@"[Network] %@ %@ - %ld - %.0fms", method, url, (long)statusCode, duration * 1000];
    IMLogLevel level = (statusCode >= 200 && statusCode < 300) ? IMLogLevelInfo : IMLogLevelWarning;
    [self logWithLevel:level tag:IMLogTagNetwork message:message];
}

+ (void)logPerformance:(NSString *)metric value:(double)value unit:(NSString *)unit {
    NSString *message = [NSString stringWithFormat:@"[Performance] %@: %.2f %@", metric, value, unit];
    [self logWithLevel:IMLogLevelInfo tag:IMLogTagPerformance message:message];
}

+ (void)logUserAction:(NSString *)action params:(NSDictionary *)params {
    IMLogUtils *instance = [self sharedInstance];
    dispatch_async(instance.logQueue, ^{
        NSMutableString *message = [NSMutableString stringWithFormat:@"[UserAction] %@", action];
        if (params.count > 0) {
            [message appendFormat:@" - %@", [self dictionaryToJSONString:params]];
        }
        [self logWithLevel:IMLogLevelInfo tag:IMLogTagGeneral message:[message copy]];
    });
}

#pragma mark - File Management

+ (NSString *)currentLogFilePath {
    return [self sharedInstance].currentLogFilePath;
}

+ (NSArray<NSString *> *)allLogFilePaths {
    IMLogUtils *instance = [self sharedInstance];
    NSArray *files = [instance.fileManager contentsOfDirectoryAtPath:instance.config.logDirectory error:nil];
    NSMutableArray *logFiles = [NSMutableArray array];
    
    for (NSString *file in files) {
        if ([file hasPrefix:@"imlog_"] && [file hasSuffix:@".log"]) {
            [logFiles addObject:[instance.config.logDirectory stringByAppendingPathComponent:file]];
        }
    }
    
    return [logFiles copy];
}

+ (NSUInteger)totalLogFileSize {
    NSArray *filePaths = [self allLogFilePaths];
    NSUInteger totalSize = 0;
    
    for (NSString *filePath in filePaths) {
        NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
        totalSize += [attributes fileSize];
    }
    
    return totalSize;
}

+ (void)cleanLogFiles {
    IMLogUtils *instance = [self sharedInstance];
    dispatch_async(instance.logQueue, ^{
        [instance performLogFileCleanup];
    });
}

+ (NSString *)compressLogFiles:(NSArray<NSString *> *)filePaths {
    // 实现日志文件压缩逻辑
    // 这里可以使用第三方库如SSZipArchive进行压缩
    return nil;
}

+ (NSString *)getLogFileContent:(NSString *)filePath {
    return [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
}

#pragma mark - Log Upload

+ (void)uploadLogFilesWithCompletion:(void(^)(BOOL success, NSError *error))completion {
    IMLogUtils *instance = [self sharedInstance];
    if (!instance.config.enableUpload || !instance.config.uploadURL) {
        if (completion) completion(NO, [NSError errorWithDomain:@"IMLogError" code:1001 userInfo:@{NSLocalizedDescriptionKey: @"日志上传未启用或URL未设置"}]);
        return;
    }
    
    // 实现日志上传逻辑
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
        // 这里实现具体的上传逻辑
        if (completion) completion(YES, nil);
    });
}

+ (void)setLogUploadURL:(NSString *)uploadURL {
    [self sharedInstance].config.uploadURL = uploadURL;
}

#pragma mark - Utility Methods

+ (NSString *)stringForTag:(IMLogTag)tag {
    static NSDictionary *tagStrings = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        tagStrings = @{
            @(IMLogTagGeneral): @"GENERAL",
            @(IMLogTagAd): @"AD",
            @(IMLogTagAdRequest): @"AD_REQUEST",
            @(IMLogTagAdShow): @"AD_SHOW",
            @(IMLogTagAdClick): @"AD_CLICK",
            @(IMLogTagNetwork): @"NETWORK",
            @(IMLogTagCache): @"CACHE",
            @(IMLogTagBidding): @"BIDDING",
            @(IMLogTagWaterfall): @"WATERFALL",
            @(IMLogTagReward): @"REWARD",
            @(IMLogTagInterstitial): @"INTERSTITIAL",
            @(IMLogTagBanner): @"BANNER",
            @(IMLogTagNative): @"NATIVE",
            @(IMLogTagSDKInit): @"SDK_INIT",
            @(IMLogTagInitialization): @"INITIALIZATION",
            @(IMLogTagError): @"ERROR",
            @(IMLogTagPerformance): @"PERFORMANCE"
        };
    });
    return tagStrings[@(tag)] ?: @"UNKNOWN";
}

+ (NSString *)stringForLevel:(IMLogLevel)level {
    static NSDictionary *levelStrings = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        levelStrings = @{
            @(IMLogLevelVerbose): @"VERBOSE",
            @(IMLogLevelDebug): @"DEBUG",
            @(IMLogLevelInfo): @"INFO",
            @(IMLogLevelWarning): @"WARNING",
            @(IMLogLevelError): @"ERROR"
        };
    });
    return levelStrings[@(level)] ?: @"UNKNOWN";
}

+ (NSString *)filterSensitiveInfo:(NSString *)message {
    if (![self sharedInstance].config.enableSensitiveFilter) {
        return message;
    }
    
    // 预编译敏感信息规则（正则 + 模板）
    static NSArray<NSDictionary *> *sensitiveRules;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSArray<NSDictionary *> *patternAndTemplate = @[
            @{@"pattern": @"(?i)(password|pwd|token|key|secret)\\s*[=:]\\s*['\"]?([^'\"\\s,}\\]]+)", @"template": @"$1=***"},
            @{@"pattern": @"(?i)(authorization)\\s*:\\s*['\"]?([^'\"\\s,}\\]]+)", @"template": @"$1=***"},
            @{@"pattern": @"\\b\\d{13,19}\\b", @"template": @"***"},
            @{@"pattern": @"\\b\\d{6,11}\\b", @"template": @"***"}
        ];
        NSMutableArray *compiled = [NSMutableArray arrayWithCapacity:patternAndTemplate.count];
        for (NSDictionary *item in patternAndTemplate) {
            NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:item[@"pattern"] options:0 error:nil];
            if (regex) {
                [compiled addObject:@{ @"regex": regex, @"template": item[@"template"] }];
            }
        }
        sensitiveRules = [compiled copy];
    });
    
    NSString *filteredMessage = message;
    for (NSDictionary *rule in sensitiveRules) {
        NSRegularExpression *regex = rule[@"regex"];
        NSString *template = rule[@"template"];
        filteredMessage = [regex stringByReplacingMatchesInString:filteredMessage options:0 range:NSMakeRange(0, filteredMessage.length) withTemplate:template];
    }
    
    return filteredMessage;
}

+ (NSString *)formatLogMessage:(IMLogLevel)level tag:(IMLogTag)tag message:(NSString *)message {
    IMLogUtils *instance = [self sharedInstance];
    NSString *timestamp = [instance.dateFormatter stringFromDate:[NSDate date]];
    NSString *levelString = [self stringForLevel:level];
    NSString *tagString = [self stringForTag:tag];
    NSString *threadInfo = [NSThread isMainThread] ? @"[Main]" : [NSString stringWithFormat:@"[%@]", [[NSThread currentThread] name] ?: @"Background"];
    
    return [NSString stringWithFormat:@"%@ %@ %@ [%@] %@", timestamp, levelString, threadInfo, tagString, message];
}

#pragma mark - Private Methods

- (void)setupCurrentLogFile {
    NSDateFormatter *fileDateFormatter = [[NSDateFormatter alloc] init];
    fileDateFormatter.dateFormat = @"yyyyMMdd_HHmmss";
    NSString *timestamp = [fileDateFormatter stringFromDate:[NSDate date]];
    
    NSString *fileName = [NSString stringWithFormat:@"imlog_%@.log", timestamp];
    self.currentLogFilePath = [self.config.logDirectory stringByAppendingPathComponent:fileName];
    
    if (![self.fileManager fileExistsAtPath:self.currentLogFilePath]) {
        [self.fileManager createFileAtPath:self.currentLogFilePath contents:nil attributes:nil];
    }
    
    self.fileHandle = [NSFileHandle fileHandleForWritingAtPath:self.currentLogFilePath];
    [self.fileHandle seekToEndOfFile];
}

- (void)startAutoCleanTimer {
    // 使用GCD定时器在日志串行队列执行清理，避免主线程负载
    if (self.cleanDispatchTimer) {
        dispatch_source_cancel(self.cleanDispatchTimer);
        self.cleanDispatchTimer = nil;
    }
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.logQueue);
    uint64_t intervalNsec = (uint64_t)(self.config.autoCleanInterval * NSEC_PER_SEC);
    dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, intervalNsec), intervalNsec, (uint64_t)(0.1 * NSEC_PER_SEC));
    dispatch_source_set_event_handler(timer, ^{
        [self performLogFileCleanup];
    });
    self.cleanDispatchTimer = timer;
    dispatch_resume(timer);
}

- (void)triggerLogCleanup {
    dispatch_async(self.logQueue, ^{
        [self performLogFileCleanup];
    });
}

- (void)performLogFileCleanup {
    NSArray *logFiles = [[self class] allLogFilePaths];
    if (logFiles.count == 0) { return; }
    NSDate *cutoffDate = [NSDate dateWithTimeIntervalSinceNow:-self.config.maxFileAge];

    // 按修改时间排序（新->旧）
    NSArray *sortedFiles = [logFiles sortedArrayUsingComparator:^NSComparisonResult(NSString *path1, NSString *path2) {
        NSDictionary *attrs1 = [self.fileManager attributesOfItemAtPath:path1 error:nil];
        NSDictionary *attrs2 = [self.fileManager attributesOfItemAtPath:path2 error:nil];
        return [[attrs2 fileModificationDate] compare:[attrs1 fileModificationDate]];
    }];

    NSString *currentPath = self.currentLogFilePath;

    // 若策略会命中当前活跃文件，则先旋转（关闭旧句柄并新建文件），再进行删除
    if (currentPath && [self.fileManager fileExistsAtPath:currentPath]) {
        NSDictionary *currentAttrs = [self.fileManager attributesOfItemAtPath:currentPath error:nil];
        NSDate *currentModDate = [currentAttrs fileModificationDate];
        NSUInteger currentIdx = [sortedFiles indexOfObject:currentPath];
        BOOL shouldDeleteByAge = (currentModDate && [currentModDate compare:cutoffDate] == NSOrderedAscending);
        BOOL shouldDeleteByCount = (currentIdx != NSNotFound && self.config.maxFileCount > 0 && currentIdx >= self.config.maxFileCount);
        if (shouldDeleteByAge || shouldDeleteByCount) {
            if (self.fileHandle) {
                [self.fileHandle closeFile];
            }
            [self setupCurrentLogFile];
            currentPath = self.currentLogFilePath;
        }
    }

    // 保护当前活跃文件，确保最终保留数量不超过配额
    NSUInteger keptTotal = currentPath ? 1 : 0; // 已保留当前活跃文件
    NSUInteger maxKeep = self.config.maxFileCount;

    for (NSString *filePath in sortedFiles) {
        if (currentPath && [filePath isEqualToString:currentPath]) {
            continue; // 跳过当前活跃文件
        }
        NSDictionary *attrs = [self.fileManager attributesOfItemAtPath:filePath error:nil];
        NSDate *modificationDate = [attrs fileModificationDate];

        BOOL deleteForAge = (modificationDate && [modificationDate compare:cutoffDate] == NSOrderedAscending);
        BOOL deleteForCount = (!deleteForAge && keptTotal >= maxKeep);

        if (deleteForAge || deleteForCount) {
            [self.fileManager removeItemAtPath:filePath error:nil];
            [IMLogUtils info:IMLogTagGeneral format:@"清理日志文件：%@", [filePath lastPathComponent]];
        } else {
            keptTotal += 1;
        }
    }
}

+ (void)logWithLevel:(IMLogLevel)level tag:(IMLogTag)tag message:(NSString *)message {
    IMLogUtils *instance = [self sharedInstance];
    if (level < instance.config.level) return;
    
    // 将过滤与格式化移到日志串行队列，减少调用线程（可能是主线程）的开销
    dispatch_async(instance.logQueue, ^{
        NSString *filteredMessage = [self filterSensitiveInfo:message];
        NSString *formattedMessage = [self formatLogMessage:level tag:tag message:filteredMessage];
        
        // 控制台输出：统一使用 os_log（Debug/Release 均一致），并显式根据敏感过滤配置标注 public/private
        if (instance.config.enableConsoleLog) {
            if (@available(iOS 10.0, *)) {
                os_log_type_t t = [self osLogTypeForLevel:level];
                if (instance.config.enableSensitiveFilter) {
                    os_log_with_type(instance.osLog, t, "%{public}@", formattedMessage);
                } else {
                    os_log_with_type(instance.osLog, t, "%{private}@", formattedMessage);
                }
            } else {
                NSLog(@"%@", formattedMessage);
            }
        }
        
        // 文件输出
        if (instance.config.enableFileLog) {
            [instance writeToFile:formattedMessage];
            // 降低刷盘频率：仅在错误级别进行同步刷盘，提升整体性能
            if (level >= IMLogLevelError && instance.fileHandle) {
                [instance.fileHandle synchronizeFile];
            }
        }
        
        // 实时监听回调（保持在主线程）
        if (instance.logMonitorCallback) {
            dispatch_async(dispatch_get_main_queue(), ^{
                instance.logMonitorCallback(formattedMessage);
            });
        }
    });
}

- (void)writeToFile:(NSString *)message {
    if (!self.fileHandle) return;
    
    NSString *logLine = [message stringByAppendingString:@"\n"];
    NSData *data = [logLine dataUsingEncoding:NSUTF8StringEncoding];
    
    [self.fileHandle writeData:data];
    // 移除每次写入后的强制刷盘，降低IO频率（错误级别在logWithLevel中单独刷盘）
    
    // 检查文件大小并进行滚动
    unsigned long long fileSize = [self.fileHandle offsetInFile];
    if (fileSize >= self.config.maxFileSize) {
        [self.fileHandle closeFile];
        [self setupCurrentLogFile];
    }
}

+ (NSString *)dictionaryToJSONString:(NSDictionary *)dictionary {
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:&error];
    if (error) return @"{}";
    return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}

- (void)dealloc {
    [self.fileHandle closeFile];
    [self.cleanTimer invalidate];
    if (self.cleanDispatchTimer) {
        dispatch_source_cancel(self.cleanDispatchTimer);
        self.cleanDispatchTimer = nil;
    }
}

#pragma mark - Missing Method Implementations

+ (void)uploadLogFiles:(NSArray<NSString *> *)filePaths completion:(nullable void(^)(BOOL success, NSError * _Nullable error))completion {
    if (completion) {
        completion(YES, nil);
    }
}

+ (void)enableRealtimeLogPopup {
    // Implementation for enabling realtime log popup
}

+ (void)disableRealtimeLogPopup {
    // Implementation for disabling realtime log popup
}

+ (void)showLogViewer {
    // Implementation for showing log viewer
}

+ (void)hideLogViewer {
    // Implementation for hiding log viewer
}

+ (void)searchLogs:(NSString *)keyword tag:(IMLogTag)tag completion:(void(^)(NSArray<NSString *> *results))completion {
    if (completion) {
        completion(@[]);
    }
}

+ (void)getLogsWithTag:(IMLogTag)tag completion:(void(^)(NSArray<NSString *> *logs))completion {
    if (completion) {
        completion(@[]);
    }
}

#pragma mark - Mediation Specific Log Implementations

+ (void)logAdLoadPerformance:(NSString *)adType 
          mediationPlatform:(NSString *)platform 
                   loadTime:(NSTimeInterval)loadTime 
                    success:(BOOL)success {
    NSString *message = [NSString stringWithFormat:@"Ad Load Performance - Type:%@ Platform:%@ Time:%.3fs Success:%@", 
                        adType, platform, loadTime, success ? @"YES" : @"NO"];
    [self info:IMLogTagPerformance format:@"%@", message];
}

+ (void)logBiddingResult:(NSString *)winnerPlatform 
            winnerECPM:(NSNumber *)winnerECPM 
         loserPlatform:(NSString *)loserPlatform 
            loserECPM:(NSNumber *)loserECPM 
             adUnitId:(NSString *)adUnitId {
    NSString *message = [NSString stringWithFormat:@"Bidding Result - Winner:%@(%.2f) Loser:%@(%.2f) AdUnit:%@", 
                        winnerPlatform, winnerECPM.doubleValue, loserPlatform, loserECPM.doubleValue, adUnitId];
    [self info:IMLogTagBidding format:@"%@", message];
}

+ (void)logMediationSwitch:(NSString *)fromPlatform 
              toPlatform:(NSString *)toPlatform 
                  reason:(NSString *)reason 
                adUnitId:(NSString *)adUnitId {
    NSString *message = [NSString stringWithFormat:@"Mediation Switch - From:%@ To:%@ Reason:%@ AdUnit:%@", 
                        fromPlatform, toPlatform, reason, adUnitId];
    [self warning:IMLogTagWaterfall format:@"%@", message];
}

#pragma mark - Real-time Log Monitoring

+ (void)addLogMonitor:(IMLogMonitorCallback)callback {
    [self sharedInstance].logMonitorCallback = callback;
}

+ (void)removeLogMonitor {
    [self sharedInstance].logMonitorCallback = nil;
}

+ (os_log_type_t)osLogTypeForLevel:(IMLogLevel)level {
#if defined(OS_LOG_TYPE_INFO)
    switch (level) {
        case IMLogLevelVerbose:
        case IMLogLevelDebug:
            return OS_LOG_TYPE_DEBUG;
        case IMLogLevelInfo:
            return OS_LOG_TYPE_INFO;
        case IMLogLevelWarning:
            return OS_LOG_TYPE_DEFAULT;
        case IMLogLevelError:
            return OS_LOG_TYPE_ERROR;
        default:
            return OS_LOG_TYPE_DEFAULT;
    }
#else
    switch (level) {
        case IMLogLevelVerbose:
        case IMLogLevelDebug:
            return OS_LOG_TYPE_DEBUG;
        case IMLogLevelInfo:
            return OS_LOG_TYPE_DEFAULT;
        case IMLogLevelWarning:
            return OS_LOG_TYPE_DEFAULT;
        case IMLogLevelError:
            return OS_LOG_TYPE_ERROR;
        default:
            return OS_LOG_TYPE_DEFAULT;
    }
#endif
}

@end